package com.adv.ems.service.impl;

import cn.hutool.json.JSONUtil;
import com.adv.ems.db.entity.*;
import com.adv.ems.enums.CollectPointWarningTypeEnum;
import com.adv.ems.manager.EnergyFeeInfoManager;
import com.adv.ems.manager.EnergyInfoManager;
import com.adv.ems.manager.InstituteInfoManager;
import com.adv.ems.manager.MeterManager;
import com.adv.ems.model.dto.CityInfoDTO;
import com.adv.ems.model.dto.ReportDataDealConfigDTO;
import com.adv.ems.model.vo.ResultVO;
import com.adv.ems.service.IncreaseValueService;
import com.adv.ems.service.WarningService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;

@Slf4j
@Service
public class IncreaseValueServiceImpl implements IncreaseValueService {
    @Resource
    WarningService warningService;
    @Resource
    EnergyInfoManager energyInfoManager;
    @Resource
    MeterManager meterManager;
    @Resource
    EnergyFeeInfoManager energyFeeInfoManager;
    @Resource
    InstituteInfoManager instituteInfoManager;

    @Override
    public Double computeRealValueByPoint(EnergyDataCumulateDO last, EnergyDataCumulateDO data, CollectPointDO point, ReportDataDealConfigDTO config) {
        if (point == null) {
            log.error("数据异常，采集点不存在【{}】", data == null ? "" : JSONUtil.toJsonStr(data));
            return 0D;
        }
        if (last == null) {
            return 0D;
        }
        double dis = data.getRealValue() - last.getRealValue();
        if (dis >= 0) {
            if (point.getMinSafeValue() != null && dis < point.getMinSafeValue()) {
                String msg = String.format("采集点两次【%s-%s】采集累计值【%s】低于采集点预设最低告警值【%s】",last.getId(), data.getId(), dis, point.getMinSafeValue());
                log.warn(msg);
                warningService.pushCollectPointWarning(data.getId(), point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.SAFE_LOW, String.valueOf(dis), msg);
            }
            if (point.getMaxSafeValue() != null && dis > point.getMaxSafeValue()) {
                String msg = String.format("采集点两次【%s-%s】采集累计值【%s】高于采集点预设最高告警值【%s】",last.getId(), data.getId(), dis, point.getMaxSafeValue());
                log.warn(msg);
                warningService.pushCollectPointWarning(data.getId(), point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.SAFE_UP, String.valueOf(dis), msg);
            }
            return dis;
        }
        if (point.getMaxValue() == null) {
            String msg = String.format("采集点两次【%s-%s】采集累计值【%s】数据异常，采集点未设置最大值无法判断仪表是否归零，本次累积归零处理",last.getId(), data.getId(), dis);
            log.warn(msg);
            warningService.pushCollectPointWarning(data.getId(), point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.SAFE_UP, String.valueOf(dis), msg);
            return 0D;
        }
        //仪表跑满数据重新从0计算情况
        double ifOver = point.getMaxValue() * config.getPerCollectDataDisOverPercentThenRollback();
        if (dis >= ifOver) {
            dis = data.getRealValue() + point.getMaxValue() - last.getRealValue();
            if (dis < ifOver) {
                log.info("预测仪表跑满数据重新读数归零成功，采集点两次【id:{},v:{}-id:{},v:{}】，采集点maxValue【{}】，配置perCollectDataDisOverPercentThenRollback【{}】",
                        last.getId(),
                        last.getRealValue(),
                        data.getId(),
                        data.getRealValue(),
                        point.getMaxValue(),
                        config.getPerCollectDataDisOverPercentThenRollback()
                );
            }else {
                String msg = String.format("预测仪表跑满数据重新读数归零失败，本次累积归零，采集点两次【id:%s,v:%s-id:%s,v:%s】，采集点maxValue【%s】，配置perCollectDataDisOverPercentThenRollback【%s】",
                        last.getId(),
                        last.getRealValue(),
                        data.getId(),
                        data.getRealValue(),
                        point.getMaxValue(),
                        config.getPerCollectDataDisOverPercentThenRollback());
                log.warn(msg);
                warningService.pushCollectPointWarning(data.getId(), point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.SAFE_UP, String.valueOf(dis), msg);
                dis = 0d;
            }
        }else {
            String msg = String.format("不符合仪表跑满情况，采集点两次【%s-%s】采集累计值【%s】数据异常，本次累积归零处理",last.getId(), data.getId(), dis);
            warningService.pushCollectPointWarning(data.getId(), point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.SAFE_UP, String.valueOf(dis), msg);
            dis = 0d;
        }
        return dis;
    }

    @Override
    public Double computeStandValueByPoint(Double increaseRealValue, CollectPointDO point) {
        ResultVO<Long> resultVO = getEnergyIdByPoint(point);
        if (!resultVO.isSuccess()) {
            return 0D;
        }
        EnergyInfoDO energyInfo = energyInfoManager.getAllMap().get(resultVO.getContent());
        if (energyInfo == null) {
            String msg = String.format("能源信息【id:%s】数据缺失，标准煤值归零",resultVO.getContent());
            warningService.pushCollectPointWarning(null, point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, resultVO.getContent().toString(), msg);
            return 0d;
        }
        if (energyInfo.getStandValuePer() == null) {
            String msg = String.format("能源信息【ID:%s】无标准煤转换率，标准煤值归零",energyInfo.getId());
            warningService.pushCollectPointWarning(null, energyInfo.getId(), EnergyInfoDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, energyInfo.getId().toString(), msg);
            return 0d;
        }
        return increaseRealValue * energyInfo.getStandValuePer();
    }

    @Override
    public Double computeCashValueByPoint(Double increaseRealValue, Date hour, CollectPointDO point) {
        ResultVO<MeterDO> resultVO = getMeterByPoint(point);
        if (!resultVO.isSuccess()) {
            return 0D;
        }
        MeterDO meter = resultVO.getContent();
        ResultVO<Long> longResultVO = energyIdByMeter(meter);
        if (!longResultVO.isSuccess()) {
            return 0d;
        }
        Long energyId = longResultVO.getContent();
        Long buildingId = meter.getBuildingId();
        Long instituteId = meter.getInstituteId();
        String areaCode = null;
        ResultVO<InstituteInfoDO> rs = getInstituteInfoByPoint(meter);
        if (rs.isSuccess() && rs.getContent().getCityInfo() != null) {
            areaCode = JSONUtil.toBean(rs.getContent().getCityInfo(), CityInfoDTO.class).getAreaCode();
        }
        EnergyFeeInfoDO item = energyFeeInfoManager.getMatchItem(energyId, hour, increaseRealValue, buildingId, instituteId, areaCode);
        if (item == null) {
            String msg = String.format("能源【energyId:%s, hour:%s, increaseRealValue:%s, buildingId:%s, instituteId:%s, areaCode:%s】未匹配到能源费率，标准煤/货币增值归零",
                    energyId,
                    hour,
                    increaseRealValue,
                    buildingId,
                    instituteId,
                    areaCode);
            warningService.pushCollectPointWarning(null, energyId, EnergyInfoDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, meter.getId().toString(), msg);
            return 0d;
        }
        return item.getValue() * increaseRealValue;
    }

    private ResultVO<InstituteInfoDO> getInstituteInfoByPoint(MeterDO meter) {
        if (meter.getInstituteId() == null) {
            String msg = String.format("智能电表【ID:%s】未关联院所，标准煤/货币增值归零",meter.getId());
            warningService.pushCollectPointWarning(null, meter.getId(), MeterDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, meter.getId().toString(), msg);
            return ResultVO.error();
        }
        InstituteInfoDO instituteInfoDO = instituteInfoManager.getAllMap().get(meter.getInstituteId());
        if (instituteInfoDO == null) {
            String msg = String.format("院所【ID:%s】数据缺失，标准煤/货币增值归零",meter.getInstituteId());
            warningService.pushCollectPointWarning(null, meter.getId(), MeterDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, meter.getInstituteId().toString(), msg);
            return ResultVO.error();
        }
        return ResultVO.success(instituteInfoDO);
    }

    private ResultVO<MeterDO> getMeterByPoint(CollectPointDO point) {
        if (point.getMeterId() == null) {
            String msg = String.format("采集点【ID:%s】未关联电表，标准煤/货币增值归零",point.getId());
            warningService.pushCollectPointWarning(null, point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, point.getId().toString(), msg);
            return ResultVO.error();
        }
        MeterDO meter = meterManager.getAllMap().get(point.getMeterId());
        if (meter == null) {
            String msg = String.format("采集点【ID:%s】对应的智能表【ID:%s】数据缺失，标准煤/货币增值归零",point.getId(), point.getMeterId());
            warningService.pushCollectPointWarning(null, point.getId(), CollectPointDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, point.getMeterId().toString(), msg);
            return ResultVO.error();
        }
        return ResultVO.success(meter);
    }

    private ResultVO<Long> energyIdByMeter(MeterDO meter) {
        if (meter.getEnergyId() == null) {
            String msg = String.format("智能表【ID:%s】无能源信息，标准煤/货币增值归零",meter.getId());
            warningService.pushCollectPointWarning(null, meter.getId(), MeterDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, meter.getId().toString(), msg);
            return ResultVO.error();
        }
        return ResultVO.success(meter.getEnergyId());
    }

    private ResultVO<Long> getEnergyIdByPoint(CollectPointDO point) {
        ResultVO<MeterDO> resultVO = getMeterByPoint(point);
        if (!resultVO.isSuccess()) {
            return ResultVO.error();
        }
        MeterDO meter = resultVO.getContent();
        if (meter.getEnergyId() == null) {
            String msg = String.format("智能表【ID:%s】无能源信息，标准煤/货币增值归零", meter.getId());
            warningService.pushCollectPointWarning(null, meter.getId(), MeterDO.class, CollectPointWarningTypeEnum.EXCEPTION_DATA, point.getMeterId().toString(), msg);
            return ResultVO.error();
        }
        return ResultVO.success(meter.getEnergyId());
    }
}
